//
// Created by madison on 2022/1/15.
//

#include <iostream>
// 必须的头文件
#include <pthread.h>
#include <unistd.h>
#include <thread>

using namespace std;

#define NUM_THREADS 5

// 线程的运行函数
void *say_hello(void *args) {
    cout << "Hello Runoob！" << endl;
}

// 以下简单的实例代码使用 pthread_create() 函数创建了 5 个线程，并接收传入的参数。
// 每个线程打印一个 "Hello Runoob!" 消息，并输出接收的参数，然后调用 pthread_exit() 终止线程。
void *PrintHello(void *threadid) {
    // 对传入的参数进行强制类型转换，由无类型指针变为整形数指针，然后再读取
    int tid = *((int *) threadid);
    cout << "Hello Runoob! 线程 ID： " << tid << endl;
    pthread_exit(NULL);
}

// 向线程传递参数
struct thread_data {
    int thread_id;
    char *message;
};

void *PrintHi(void *threadarg) {
    struct thread_data *my_data;

    my_data = (struct thread_data *) threadarg;

    cout << "Thread ID : " << my_data->thread_id;
    cout << " Message : " << my_data->message << endl;

    pthread_exit(NULL);
}

int main() {
    // 定义线程的 id 变量，多个变量使用数组
    pthread_t tids[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; ++i) {
        //参数依次是：创建的线程id，线程参数，调用的函数，传入的函数参数
        int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
        if (ret != 0) {
            cout << "pthread_create error: error_code=" << ret << endl;
        }
    }

    sleep(5);
    cout << "-----------" << endl;


    // 以下简单的实例代码使用 pthread_create() 函数创建了 5 个线程，并接收传入的参数
    pthread_t threads[NUM_THREADS];
    int indexes[NUM_THREADS];// 用数组来保存i的值
    for (int i = 0; i < NUM_THREADS; i++) {
        cout << "main() : 创建线程, " << i << endl;
        indexes[i] = i; //先保存i的值
        // 传入的时候必须强制转换为void* 类型，即无类型指针
        int rc = pthread_create(&threads[i], NULL,
                                PrintHello, (void *) &(indexes[i]));
        if (rc) {
            cout << "Error:无法创建线程," << rc << endl;
            exit(-1);
        }
    }

    sleep(5);
    cout << "-----------" << endl;

    // 向线程传递参数
    pthread_t threadsHi[NUM_THREADS];
    struct thread_data td[NUM_THREADS];
    int rc;
    int i;

    for (i = 0; i < NUM_THREADS; i++) {
        cout << "main() : creating thread, " << i << endl;
        td[i].thread_id = i;
        td[i].message = (char *) "This is message";
        rc = pthread_create(&threadsHi[i], NULL,
                            PrintHi, (void *) &td[i]);
        if (rc) {
            cout << "Error:unable to create thread," << rc << endl;
            exit(-1);
        }
    }


    sleep(5);
    cout << "-----------" << endl;

    // 连接和分离线程
    void fun();
    fun();


    sleep(5);
    cout << "-----------" << endl;

    void fun1();
    fun1();

    //等各个线程退出后，进程才结束，否则进程强制结束了，线程可能还没反应过来；
    pthread_exit(NULL);
    return 0;
}

// 连接和分离线程
void *wait(void *t) {
    int i;
    long tid;

    tid = (long) t;

    sleep(1);
    cout << "Sleeping in thread " << endl;
    cout << "Thread with id : " << tid << "  ...exiting " << endl;
    pthread_exit(NULL);
}

void fun() {
    int rc;
    int i;
    pthread_t threads[NUM_THREADS];
    pthread_attr_t attr;
    void *status;

    // 初始化并设置线程为可连接的（joinable）
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    for (i = 0; i < NUM_THREADS; i++) {
        cout << "main() : creating thread, " << i << endl;
        rc = pthread_create(&threads[i], NULL, wait, (void *) &i);
        if (rc) {
            cout << "Error:unable to create thread," << rc << endl;
            exit(-1);
        }
    }

    // 删除属性，并等待其他线程
    pthread_attr_destroy(&attr);
    for (i = 0; i < NUM_THREADS; i++) {
        rc = pthread_join(threads[i], &status);
        if (rc) {
            cout << "Error:unable to join," << rc << endl;
            exit(-1);
        }
        cout << "Main: completed thread id :" << i;
        cout << "  exiting with status :" << status << endl;
    }

    cout << "Main: program exiting." << endl;
    pthread_exit(NULL);
}


// 一个虚拟函数
void foo(int Z) {
    for (int i = 0; i < Z; i++) {
        cout << "线程使用函数指针作为可调用参数\n";
    }
}

// 可调用对象
class thread_obj {
public:
    void operator()(int x) {
        for (int i = 0; i < x; i++)
            cout << "线程使用函数对象作为可调用参数\n";
    }
};

void fun1() {
    cout << "线程 1 、2 、3 "
            "独立运行" << endl;

    // 函数指针
    thread th1(foo, 3);

    // 函数对象
    thread th2(thread_obj(), 3);

    // 定义 Lambda 表达式
    auto f = [](int x) {
        for (int i = 0; i < x; i++)
            cout << "线程使用 lambda 表达式作为可调用参数\n";
    };

    // 线程通过使用 lambda 表达式作为可调用的参数
    thread th3(f, 3);

    // 等待线程完成
    // 等待线程 t1 完成
    th1.join();

    // 等待线程 t2 完成
    th2.join();

    // 等待线程 t3 完成
    th3.join();
}